<?php

namespace decrypt;

class GotoDecode
{
	private $filename;
	private $data;
	private $goto_preg;
	private $preg_s;
	private $preg_if;
	private $stop_preg;
	private $matches;
	private $match_ifarr;

	public function __construct($filename)
	{
		$this->filename = $filename;
		$this->data = file_get_contents($this->filename);
		$this->data = trim($this->data, '?>');
		$this->goto_preg = '/(?<=goto)[\s]+([^;\s]+)[\s]*(?=;)/isU';
		$this->preg_s = '/\/\*[\s\S]+(?=\*\/)\*\//isU';
		$this->preg_if = '/if$([^;]+)$\s*goto\s+(\w+);/isU';
		$this->stop_preg = '/[\s\S]*(return|exit|die|goto)[^;]*;/isU';
		preg_match_all($this->goto_preg, $this->data, $this->matches);
		$this->match_ifarr = [];
		$this->preprocess();
	}

	public function preprocess()
	{
		if (preg_match($this->preg_s, $this->data, $match_s)) {
			$this->data = preg_replace($this->preg_s, '', $this->data);
		}

		foreach ($this->matches[1] as $key => $value) {
			$this->data = preg_replace('/' . $value . ';/', '_lblindex_' . $key . ';', $this->data);
			$this->data = preg_replace('/' . $value . ':/', '_lblindex_' . $key . ':', $this->data);
		}

		if (preg_match_all($this->preg_if, $this->data, $match_if)) {
			foreach ($match_if[0] as $key => $val) {
				$this->match_ifarr[$match_if[2][$key]]['value'] = $match_if[2][$key];
				$this->match_ifarr[$match_if[2][$key]]['all_if'] = $match_if[0][$key];
				$this->match_ifarr[$match_if[2][$key]]['key'] = $key;
			}
		}
	}

	public function decode()
	{
		set_time_limit(0);

		if (empty($this->data)) exit('数据获取失败！');

		$value_index = '_lblindex_0';

		foreach ($this->matches[1] as $key => $value) {
			$data_jiemi = $this->jiemi($this->data, $value_index, $key);
			$this->data = $data_jiemi['data'];
			$value_index = $data_jiemi['index'];

			if (empty($value_index)) {
				$this->data = $this->prety($this->data);
				return $this->data;
			}
		}

		return '';
	}

	private function jiemi($data, $value, $key)
	{
		$pos_start = strpos($data, $value . ";");
		$pos_end = strpos($data, $value . ":");

		if (isset($this->match_ifarr[$value]['value'])) {
			$data = $this->jiemi_if($data, $this->match_ifarr[$value]['all_if'], $this->match_ifarr[$value]['value'], $key);
		} else {
			if ($pos_end > 0 && $pos_end > $pos_start) {
				$str_prev_arr = preg_split("/goto[\s]+" . $value . ";/isU", $data, 2, PREG_SPLIT_NO_EMPTY);
				$str_prev = isset($str_prev_arr[0]) ? $str_prev_arr[0] : ' ';
				$str_after_arr = preg_split("/" . $value . ":/isU", $data, 2, PREG_SPLIT_NO_EMPTY);
				$str_after = isset($str_after_arr[1]) ? $str_after_arr[1] : ' ';

				$str_temp = $this->get_end($value, $str_after, $key);
				isset($str_prev_arr[1]) ? $str_prev_arr[1] : $str_prev_arr[1] = '';
				$str_center = substr($str_prev_arr[1], 0, strpos($str_prev_arr[1], $value . ":"));
				$str_end = substr($str_after, strpos($str_after, $str_temp) + strlen($str_temp));
				$data = $str_prev . $str_temp . $str_center . $str_end;
			} else {
				$data = preg_replace('/goto\s+' . $value . ';/isU', '', $data);
				$data = preg_replace('/' . $value . ':/isU', '', $data);
			}
		}

		$goto_arr = preg_split("/goto[\s]+/", $data, 2, PREG_SPLIT_NO_EMPTY);
		if (isset($goto_arr[1])) {
			$value_index = substr($goto_arr[1], 0, strpos($goto_arr[1], ';'));
		} else {
			$value_index = '';
		}

		return array('data' => $data, 'index' => $value_index);
	}

	private function prety($data)
	{
		$data = str_replace("} ", "} " . PHP_EOL, $data);
		$data = str_replace("; ", "; " . PHP_EOL, $data);
		$data = str_replace(" { ", " { " . PHP_EOL, $data);
		return $data;
	}

	private function jiemi_if($data, $all_if, $value, $key)
	{
		$data_1 = str_replace($all_if, 'goto ' . $value . ';', $data);
		$str_prev_arr = preg_split("/goto[\s]+" . $value . ";/isU", $data_1, 2, PREG_SPLIT_NO_EMPTY);
		$str_prev = $str_prev_arr[0];
		$str_after_arr = preg_split("/" . $value . ":/", $data_1, 2, PREG_SPLIT_NO_EMPTY);
		$str_after = isset($str_after_arr[1]) ? $str_after_arr[1] : $str_after_arr[1] = '';
		isset($str_prev_arr[1]) ? $str_prev_arr[1] : $str_prev_arr[1] = '';
		$str_center = substr($str_prev_arr[1], 0, strpos($str_prev_arr[1], $value . ":"));
		$str_temp = $this->get_end($value, $str_after, $key);
		$str_end = substr($str_after, strpos($str_after, $str_temp) + strlen($str_temp));
		$data_1 = $str_prev . $str_temp . $str_center . $str_end;
		$data_1 = preg_replace('/goto\s+' . $value . ';/', '', $data_1);
		$data_1 = str_replace($value . ':', '', $data_1);

		$data_0 = str_replace($all_if, '', $data);
		$data_0 = preg_replace('/goto\s+' . $value . ';/', '', $data_0);
		$data_0 = str_replace($value . ':', '', $data_0);

		preg_match($this->goto_preg, $data_0, $match_goto);
		$data_part = preg_split("/goto[\s]+" . $match_goto[1] . ";/isU", $data_0, 2, PREG_SPLIT_NO_EMPTY);

		if (strpos($data_part[0], '_lblindex_') !== false) {
			echo $all_if . '选了true <br/>';
			return $data_1;
		} else {
			echo $all_if . '选了false<br/>';
			return $data_0;
		}
	}

	private function get_end($value, $str_after, $key)
	{
		$str_temp = '';
		if (preg_match_all($this->stop_preg, $str_after, $stop_arr_all)) {
			isset($stop_arr_all[0][1]) ? $stop_arr_all[0][1] : $stop_arr_all[0][1] = '';
			if (strpos($stop_arr_all[0][0], '{') !== false || strpos($stop_arr_all[0][0], 'if') !== false) {
				$str_temp = $stop_arr_all[0][0] . $stop_arr_all[0][1];
			} else {
				$str_temp = $stop_arr_all[0][0];
			}
		} else {
			$str_temp = $str_after;
		}
		return $str_temp;
	}
}
